package net.lab1024.sa.admin.module.system.user.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.place.domain.vo.PlaceVO;
import net.lab1024.sa.admin.module.business.place.service.RSchoolService;
import net.lab1024.sa.admin.module.system.department.service.DepartmentService;
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO;
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
import net.lab1024.sa.admin.module.system.role.service.RoleMenuService;
import net.lab1024.sa.admin.module.system.role.service.RoleService;
import net.lab1024.sa.admin.module.system.sms.SmsCodeService;
import net.lab1024.sa.admin.module.system.user.domain.Enity.UserEntity;
import net.lab1024.sa.admin.module.system.user.domain.UserLoginForm;
import net.lab1024.sa.admin.module.system.user.domain.UserLoginResultVO;
import net.lab1024.sa.admin.module.system.user.domain.form.UserAddForm;
import net.lab1024.sa.admin.util.IdGenerator;
import net.lab1024.sa.admin.util.RandomNickname;
import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.constant.RequestHeaderConst;
import net.lab1024.sa.base.common.constant.StringConst;
import net.lab1024.sa.admin.module.system.user.domain.RequestUser;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.UserPermission;
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartEnumUtil;
import net.lab1024.sa.base.common.util.SmartIpUtil;
import net.lab1024.sa.base.constant.LoginDeviceEnum;
import net.lab1024.sa.base.module.support.captcha.CaptchaService;
import net.lab1024.sa.base.module.support.captcha.domain.CaptchaVO;
import net.lab1024.sa.base.module.support.config.ConfigService;
import net.lab1024.sa.base.module.support.loginlog.LoginLogResultEnum;
import net.lab1024.sa.base.module.support.loginlog.LoginLogService;
import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogEntity;
import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogVO;
import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailEntity;
import net.lab1024.sa.base.module.support.securityprotect.service.ProtectLoginService;
import net.lab1024.sa.base.module.support.securityprotect.service.ProtectPasswordService;
import org.apache.commons.lang3.StringUtils;
import org.apache.xmlbeans.UserType;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * 登录
 *
 * @Author 1024创新实验室: 开云
 * @Date 2021-12-01 22:56:34
 
 
 * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
 */
@Slf4j
@Service
public class UserLoginService {


    /**
     * 万能密码的 sa token loginId 前缀
     */
    private static final String SUPER_PASSWORD_LOGIN_ID_PREFIX = "S";

    /**
     * 最大在线缓存人数
     */
    private static final long CACHE_MAX_ONLINE_PERSON_COUNT = 1000L;
    private static final long USER_ROLE = 40L;
    private static final long JDY_ROLE = 40L;
    /**
     * 登录信息二级缓存
     */
    private final ConcurrentMap<String, RequestUser> loginUserCache = new ConcurrentLinkedHashMap.Builder<String, RequestUser>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();


    /**
     * 权限 缓存
     */
    private final ConcurrentMap<String, UserPermission> permissionCache = new ConcurrentLinkedHashMap.Builder<String, UserPermission>().maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();

    @Resource
    private EmployeeService employeeService;
    @Resource
    private UserService userService;

    @Resource
    private DepartmentService departmentService;
    @Resource
    private RSchoolService schoolService;
    @Resource
    private CaptchaService captchaService;
    @Resource
    private SmsCodeService smsCodeService;
    @Resource
    private ConfigService configService;

    @Resource
    private LoginLogService loginLogService;

    @Resource
    private RoleEmployeeService roleEmployeeService;

    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private ProtectLoginService protectLoginService;

    @Resource
    private RoleService roleService;
    @Resource
    private ProtectPasswordService profectPasswordService;

    /**
     * 获取验证码
     */
    public ResponseDTO<CaptchaVO> getCaptcha() {
        return ResponseDTO.ok(captchaService.generateCaptcha());
    }

    /**
     * 员工登陆
     *
     * @return 返回用户登录信息
     */
    public ResponseDTO<UserLoginResultVO> login(UserLoginForm loginForm, String ip, String userAgent) {

        LoginDeviceEnum loginDeviceEnum = SmartEnumUtil.getEnumByValue(loginForm.getLoginDevice(), LoginDeviceEnum.class);
        if (loginDeviceEnum == null) {
            return ResponseDTO.userErrorParam("登录设备暂不支持！");
        }

        // 校验 图形验证码
//        ResponseDTO<String> checkCaptcha = captchaService.checkCaptcha(loginForm);
//        if (!checkCaptcha.getOk()) {
//            return ResponseDTO.error(UserErrorCode.PARAM_ERROR, checkCaptcha.getMsg());
//        }
        ResponseDTO<String> checkSmsCode = smsCodeService.verifyCode(loginForm.getPhone(), loginForm.getCaptchaCode());
        if (!checkSmsCode.getOk()) {
            return ResponseDTO.error(UserErrorCode.PARAM_ERROR, checkSmsCode.getMsg());
        }
        // 验证电话
        UserEntity userEntity = userService.getByPhone(loginForm.getPhone());

        if (null == userEntity && PhoneUtil.isMobile(loginForm.getPhone())) {
            // 手机号不存在，创建新用户
            UserAddForm newUserEntity = new UserAddForm();
            Long id = IdGenerator.generateId();
            newUserEntity.setUserId(String.valueOf(id));
            newUserEntity.setPhone(loginForm.getPhone());
            newUserEntity.setPetName(RandomNickname.getName(1));
            userService.add(newUserEntity);
            userEntity = userService.getByPhone(loginForm.getPhone());
        }
        // 验证账号状态
        if (userEntity.isDel()) {
            saveLoginLog(userEntity, ip, userAgent, "账号已禁用", LoginLogResultEnum.LOGIN_FAIL);
            return ResponseDTO.userErrorParam("您的账号已被禁用,请联系工作人员！");
        }

//        // 解密前端加密的密码
//        String requestPassword = profectPasswordService.decryptPassword(loginForm.getPassword());
//
//        // 验证密码 是否为万能密码
//        String superPassword = configService.getConfigValue(ConfigKeyEnum.SUPER_PASSWORD);
//        boolean superPasswordFlag = superPassword.equals(requestPassword);
//
//        // 万能密码特殊操作
//        if (superPasswordFlag) {
//
//            // 对于万能密码：受限制sa token 要求loginId唯一，万能密码只能插入一段uuid
//            String saTokenLoginId = SUPER_PASSWORD_LOGIN_ID_PREFIX + StringConst.COLON + UUID.randomUUID().toString().replace("-", "") + StringConst.COLON + employeeEntity.getEmployeeId();
//            // 万能密码登录只能登录30分钟
//            StpUtil.login(saTokenLoginId, 1800);
//
//        } else {

            // 按照等保登录要求，进行登录失败次数校验
            ResponseDTO<LoginFailEntity> loginFailEntityResponseDTO = protectLoginService.checkLogin(userEntity.getUserId(), Math.toIntExact(userEntity.getUserType()));
            if (!loginFailEntityResponseDTO.getOk()) {
                return ResponseDTO.error(loginFailEntityResponseDTO);
            }

//            // 密码错误
//            if (!employeeEntity.getLoginPwd().equals(EmployeeService.getEncryptPwd(requestPassword))) {
//                // 记录登录失败
//                saveLoginLog(employeeEntity, ip, userAgent, "密码错误", LoginLogResultEnum.LOGIN_FAIL);
//                // 记录等级保护次数
//                String msg = protectLoginService.recordLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, employeeEntity.getLoginName(), loginFailEntityResponseDTO.getData());
//                return msg == null ? ResponseDTO.userErrorParam("登录名或密码错误！") : ResponseDTO.error(UserErrorCode.LOGIN_FAIL_WILL_LOCK, msg);
//            }

            String saTokenLoginId = userEntity.getUserType() + StringConst.COLON + userEntity.getUserId();
            // 登录
            StpUtil.login(saTokenLoginId, String.valueOf(loginDeviceEnum.getDesc()));
//        }

        // 获取员工信息
        RequestUser requestEmployee = loadLoginInfo(userEntity);

        // 放入缓存
        loginUserCache.put(userEntity.getUserId(), requestEmployee);

        // 移除登录失败
        protectLoginService.removeLoginFail(userEntity.getUserId(), UserTypeEnum.ADMIN_EMPLOYEE);

        // 获取登录结果信息
        UserLoginResultVO loginResultVO = getLoginResult(requestEmployee);

//        //保存登录记录
//        saveLoginLog(userEntity, ip, userAgent, superPasswordFlag ? "万能密码登录" : loginDeviceEnum.getDesc(), LoginLogResultEnum.LOGIN_SUCCESS);
        saveLoginLog(userEntity, ip, userAgent, loginDeviceEnum.getDesc(), LoginLogResultEnum.LOGIN_SUCCESS);
        // 设置 token
        loginResultVO.setToken(StpUtil.getTokenValue());

        // 清除权限缓存
        permissionCache.remove(userEntity.getUserId());

        return ResponseDTO.ok(loginResultVO);
    }


    /**
     * 获取登录结果信息
     */
    public UserLoginResultVO getLoginResult(RequestUser requestEmployee) {

        // 基础信息
        UserLoginResultVO loginResultVO = SmartBeanUtil.copy(requestEmployee, UserLoginResultVO.class);
        List<RoleVO> roleList = new ArrayList<>();
        if(requestEmployee.getUserType() == 1L){
            roleList.add(roleService.getRoleById(USER_ROLE).getData());
        }else {
            roleList.add(roleService.getRoleById(JDY_ROLE).getData());
        }
        // 前端菜单和功能点清单
//        List<RoleVO> roleList = roleEmployeeService.getRoleIdList(40L);
        List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), false);
        loginResultVO.setMenuList(menuAndPointsList);

        // 更新下后端权限缓存
        UserPermission userPermission = getUserPermission(requestEmployee.getUserType());
        permissionCache.put(requestEmployee.getUserId(), userPermission);

        // 上次登录信息
        LoginLogVO loginLogVO = loginLogService.queryLastByUserIdString(requestEmployee.getUserId(), Math.toIntExact(requestEmployee.getUserType()), LoginLogResultEnum.LOGIN_SUCCESS);
        if (loginLogVO != null) {
            loginResultVO.setLastLoginIp(loginLogVO.getLoginIp());
            loginResultVO.setLastLoginIpRegion(loginLogVO.getLoginIpRegion());
            loginResultVO.setLastLoginTime(loginLogVO.getCreateTime());
            loginResultVO.setLastLoginUserAgent(loginLogVO.getUserAgent());
        }

        return loginResultVO;
    }


    /**
     * 获取登录的用户信息
     */
    private RequestUser loadLoginInfo(UserEntity employeeEntity) {

        // 基础信息
        RequestUser requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestUser.class);
        requestEmployee.setUserId(employeeEntity.getUserId());
        requestEmployee.setUserType(employeeEntity.getUserType());

//        // 部门信息
//        DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId());
//        requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName());
        // 学校信息
        PlaceVO school = schoolService.getSchoolById(employeeEntity.getSchoolId());
        requestEmployee.setSchoolName(null == school ? StringConst.EMPTY : school.getPlaceName());
        return requestEmployee;
    }


    /**
     * 根据登陆token 获取员请求工信息
     */
    public RequestUser getLoginEmployee(String loginId, HttpServletRequest request) {
        if (loginId == null) {
            return null;
        }

        String requestEmployeeId = getEmployeeIdByLoginId(loginId);
        if (requestEmployeeId == null) {
            return null;
        }

        RequestUser requestEmployee = loginUserCache.get(requestEmployeeId);
        if (requestEmployee == null) {
            // 员工基本信息
            UserEntity employeeEntity = userService.getById(requestEmployeeId);
            if (employeeEntity == null) {
                return null;
            }

            requestEmployee = this.loadLoginInfo(employeeEntity);
            loginUserCache.put(requestEmployeeId, requestEmployee);
        }
        if(userService.UPDATE){
            UserEntity employeeEntity = userService.getById(requestEmployeeId);
            if (employeeEntity == null) {
                return null;
            }
            requestEmployee = this.loadLoginInfo(employeeEntity);
            loginUserCache.put(requestEmployeeId, requestEmployee);
            userService.UPDATE = false;
        }
        // 更新请求ip和user agent
        requestEmployee.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
        requestEmployee.setIp(ServletUtil.getClientIP(request));

        return requestEmployee;
    }

    /**
     * 根据 loginId 获取 员工id
     */
    public String getEmployeeIdByLoginId(String loginId) {

        if (loginId == null) {
            return null;
        }

        try {
            // 如果是 万能密码 登录的用户
            String employeeIdStr = null;
//            if (loginId.startsWith(SUPER_PASSWORD_LOGIN_ID_PREFIX)) {
//                employeeIdStr = loginId.split(StringConst.COLON)[2];
//            } else {
                employeeIdStr = loginId.substring(2);
//            }

            return employeeIdStr;
        } catch (Exception e) {
            log.error("loginId parse error , loginId : {}", loginId, e);
            return null;
        }
    }


    /**
     * 退出登录
     */
    public ResponseDTO<String> logout(String token, RequestUser requestUser) {

        // sa token 登出
        StpUtil.logoutByTokenValue(token);

        // 清空登录信息缓存
        loginUserCache.remove(requestUser.getUserId());
        System.out.println("清空登录信息缓存"+loginUserCache.get(requestUser.getUserId()));
        //保存登出日志
        LoginLogEntity loginEntity = LoginLogEntity.builder()
                .userId(Long.valueOf(requestUser.getUserId()))
                .userType(Math.toIntExact(requestUser.getUserType()))
                .userName(requestUser.getPetName())
                .userAgent(requestUser.getUserAgent())
                .loginIp(requestUser.getIp())
                .loginIpRegion(SmartIpUtil.getRegion(requestUser.getIp()))
                .loginResult(LoginLogResultEnum.LOGIN_OUT.getValue())
                .createTime(LocalDateTime.now())
                .build();
        loginLogService.log(loginEntity);

        return ResponseDTO.ok();
    }

    /**
     * 保存登录日志
     */
    private void saveLoginLog(UserEntity employeeEntity, String ip, String userAgent, String remark, LoginLogResultEnum result) {
        LoginLogEntity loginEntity = LoginLogEntity.builder()
                .userId(Long.valueOf(employeeEntity.getUserId()))
                .userType(Math.toIntExact(employeeEntity.getUserType()))
                .userName(employeeEntity.getPetName())
                .userAgent(userAgent)
                .loginIp(ip)
                .loginIpRegion(SmartIpUtil.getRegion(ip))
                .remark(remark)
                .loginResult(result.getValue())
                .createTime(LocalDateTime.now())
                .build();
        loginLogService.log(loginEntity);
    }
//
//    @Override
//    public List<String> getPermissionList(Object loginId, String loginType) {
//        Long employeeId = this.getEmployeeIdByLoginId((String) loginId);
//        if (employeeId == null) {
//            return Collections.emptyList();
//        }
//
//        UserPermission userPermission = permissionCache.get(employeeId);
//        if (userPermission == null) {
//            userPermission = getUserPermission(employeeId);
//            permissionCache.put(employeeId, userPermission);
//        }
//
//        return userPermission.getPermissionList();
//    }
//
//    @Override
//    public List<String> getRoleList(Object loginId, String loginType) {
//        Long employeeId = this.getEmployeeIdByLoginId((String) loginId);
//        if (employeeId == null) {
//            return Collections.emptyList();
//        }
//
//        UserPermission userPermission = permissionCache.get(employeeId);
//        if (userPermission == null) {
//            userPermission = getUserPermission(employeeId);
//            permissionCache.put(employeeId, userPermission);
//        }
//        return userPermission.getRoleList();
//    }
//
    /**
     * 获取用户的权限（包含 角色列表、权限列表）
     */
    private UserPermission getUserPermission(Long UserType) {

        UserPermission userPermission = new UserPermission();
        userPermission.setPermissionList(new ArrayList<>());
        userPermission.setRoleList(new ArrayList<>());

        // 角色列表
        List<RoleVO> roleList = new ArrayList<>();
        if(UserType == 1L){
            roleList.add(roleService.getRoleById(USER_ROLE).getData());
        }else {
            roleList.add(roleService.getRoleById(JDY_ROLE).getData());
        }
        userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet()));

        // 前端菜单和功能点清单
//        EmployeeEntity employeeEntity = employeeService.getById(employeeId);

        List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), false);

        // 权限列表
        HashSet<String> permissionSet = new HashSet<>();
        for (MenuVO menu : menuAndPointsList) {
            if (menu.getPermsType() == null) {
                continue;
            }
            String perms = menu.getApiPerms();
            if (StringUtils.isEmpty(perms)) {
                continue;
            }
            //接口权限
            String[] split = perms.split(",");
            permissionSet.addAll(Arrays.asList(split));
        }
        userPermission.getPermissionList().addAll(permissionSet);

        return userPermission;
    }
    //更新二级登录缓存中用户信息
}
